package com.ayf.payment.game.api.task.gift;

import com.ayf.payment.game.api.entity.GameInfoGiftLog;
import com.ayf.payment.game.api.service.GameInfoGiftLogService;
import com.ayf.payment.game.api.service.GameInfoGiftService;
import com.ayf.payment.game.api.utils.DateUtils;
import com.ayf.payment.game.api.utils.SnowFlakeUtils;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.swwx.charm.commons.lang.utils.LogPortal;
import com.swwx.charm.zookeeper.exception.GetLockFailedException;
import com.swwx.charm.zookeeper.exception.ReleaseLockFailedException;
import com.swwx.charm.zookeeper.lock.DistributedLock;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * @Author: zh-liang
 * @Date : 2021-05-10
 */
@Component
public abstract class GiftResetTaskImpl {

    @Resource
    private GameInfoGiftService gameInfoGiftService;
    @Resource
    private GameInfoGiftLogService gameInfoGiftLogService;

    protected void run(DistributedLock distributedLock) {
        boolean lock = false;
        String traceId = SnowFlakeUtils.getTraceId();
        String lockName = this.getClass().getSimpleName().concat(System.getenv("XY_GAME_PAY_LOCK_FLAG"));
        try {
            if (lock = distributedLock.getLock(lockName)) {
                LogPortal.info("{} >>> get lock and run {} ", traceId, lockName);
                PageHelper.startPage(1, 200);
                List<GameInfoGiftLog> listLog = gameInfoGiftService.selectYesterdayInfo();
                PageInfo<GameInfoGiftLog> pageInfo = new PageInfo<>(listLog);
                long count = pageInfo.getTotal();
                LogPortal.info("{} >>> [{}]处理总条数[{}]", traceId, lockName, count);
                if (count <= 0) {
                    return;
                }
                final int pageSize = 200;
                //初始化信号
                final CountDownLatch countDownLatch = new CountDownLatch(pageInfo.getPages());
                for (int i = 1; i <= pageInfo.getPages(); i++) {
                    int a = i;
                    PageHelper.startPage(i, pageSize);
                    List<GameInfoGiftLog> list = gameInfoGiftService.selectYesterdayInfo();
                    LogPortal.info("{} >>> {} 开始处理第[{}/{}]页游戏礼包重置，共[{}]条", traceId, lockName, i, pageInfo.getPages(), list.size());
                    submit(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                list.forEach(d -> d.setDateIndex(DateUtils.dateToInteger(DateUtils.getDayBeforeDay(1))));
                                gameInfoGiftLogService.addList(list);
                                LogPortal.info("{} >>> {} 第[{}]页游戏礼包重置处理完成", traceId, lockName, a);
                            } catch (Exception e) {
                                LogPortal.error("{} >>> {} 处理第[{}]页游戏礼包重置时发生了{}异常，错误描述:{}", e,
                                        traceId, lockName, a, e.getClass().getName(), e.getMessage());
                            } finally {
                                //线程执行完成之后标记信号表示完成
                                countDownLatch.countDown();
                            }
                        }
                    });
                }
                //等待线程池任务执行完毕
                countDownLatch.await();
                gameInfoGiftService.reset();
            } else {
                LogPortal.info("{} >>> {} do not get lock ", traceId, lockName);
            }
        } catch (GetLockFailedException e) {
            LogPortal.error("{} >>> [DISTRIBUTED_LOCK_ACQUIRE_FAILED_ZK] 分布式锁获取失败,锁名称为:{}", traceId, lockName);
            LogPortal.error("{} >>> {} 获取lock失败", e, traceId, lockName);
        } catch (Exception e) {
            LogPortal.error("{} >>> {} 任务执行出错 ", e, traceId, lockName);
        } finally {
            if (lock) {
                LogPortal.info(traceId + " >>> " + lockName + " finished.");
                try {
                    distributedLock.releaseLock(lockName);
                } catch (ReleaseLockFailedException e) {
                    LogPortal.error("{} >>> [DISTRIBUTED_LOCK_RELEASE_FAILED_ZK] 分布式锁释放失败,锁名称为:{}", traceId, lockName);
                    LogPortal.error("{} >>> {} 释放失败", e, traceId, lockName);
                }
            }
        }
    }

    public abstract void submit(Runnable task);

}
